/*
Copyright (C) 2018-2019 de4dot@gmail.com

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

mod enums;
mod handlers;
mod handlers_3dnow;
#[cfg(not(feature = "no_evex"))]
mod handlers_evex;
mod handlers_fpu;
mod handlers_legacy;
mod handlers_tables;
#[cfg(any(not(feature = "no_vex"), not(feature = "no_xop")))]
mod handlers_vex;
mod table_de;
#[cfg(test)]
pub(crate) mod tests;

use self::handlers::OpCodeHandler;
use self::handlers_tables::TABLES;
use super::iced_constants::IcedConstants;
use super::*;
#[cfg(has_fused_iterator)]
use core::iter::FusedIterator;
use core::{cmp, fmt, mem, ptr, u32};

// 26,2E,36,3E,64,65,66,67,F0,F2,F3
static PREFIXES1632: [u32; 8] = [0x0000_0000, 0x4040_4040, 0x0000_0000, 0x0000_00F0, 0x0000_0000, 0x0000_0000, 0x0000_0000, 0x000D_0000];
// 26,2E,36,3E,64,65,66,67,F0,F2,F3 and 40-4F
static PREFIXES64: [u32; 8] = [0x0000_0000, 0x4040_4040, 0x0000_FFFF, 0x0000_00F0, 0x0000_0000, 0x0000_0000, 0x0000_0000, 0x000D_0000];

static MEM_REGS_16: [(Register, Register); 8] = [
	(Register::BX, Register::SI),
	(Register::BX, Register::DI),
	(Register::BP, Register::SI),
	(Register::BP, Register::DI),
	(Register::SI, Register::None),
	(Register::DI, Register::None),
	(Register::BP, Register::None),
	(Register::BX, Register::None),
];

// GENERATOR-BEGIN: OpSize
// ⚠️This was generated by GENERATOR!🦹‍♂️
#[derive(Copy, Clone, Eq, PartialEq)]
#[allow(dead_code)]
pub(crate) enum OpSize {
	Size16,
	Size32,
	Size64,
}
#[cfg_attr(feature = "cargo-fmt", rustfmt::skip)]
static GEN_DEBUG_OP_SIZE: [&str; 3] = [
	"Size16",
	"Size32",
	"Size64",
];
impl fmt::Debug for OpSize {
	#[inline]
	fn fmt<'a>(&self, f: &mut fmt::Formatter<'a>) -> fmt::Result {
		write!(f, "{}", GEN_DEBUG_OP_SIZE[*self as usize])?;
		Ok(())
	}
}
impl Default for OpSize {
	#[cfg_attr(has_must_use, must_use)]
	#[inline]
	fn default() -> Self {
		OpSize::Size16
	}
}
// GENERATOR-END: OpSize

// GENERATOR-BEGIN: DecoderOptions
// ⚠️This was generated by GENERATOR!🦹‍♂️
/// Decoder options
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct DecoderOptions;
impl DecoderOptions {
	/// No option is enabled
	pub const NONE: u32 = 0x0000_0000;
	/// Disable some checks for invalid encodings of instructions, eg. most instructions can't use a `LOCK` prefix so if one is found, they're decoded as [`Code::INVALID`] unless this option is enabled.
	///
	/// [`Code::INVALID`]: enum.Code.html#variant.INVALID
	pub const NO_INVALID_CHECK: u32 = 0x0000_0001;
	/// AMD branch decoder: allow 16-bit branch/ret instructions in 64-bit mode
	pub const AMD_BRANCHES: u32 = 0x0000_0002;
	/// Decode opcodes `0F0D` and `0F18-0F1F` as reserved-nop instructions (eg. [`Code::ReservedNop_rm32_r32_0F1D`])
	///
	/// [`Code::ReservedNop_rm32_r32_0F1D`]: enum.Code.html#variant.ReservedNop_rm32_r32_0F1D
	pub const FORCE_RESERVED_NOP: u32 = 0x0000_0004;
	/// Decode `UMOV` instructions (eg. [`Code::Umov_r32_rm32`])
	///
	/// [`Code::Umov_r32_rm32`]: enum.Code.html#variant.Umov_r32_rm32
	pub const UMOV: u32 = 0x0000_0008;
	/// Decode `XBTS`/`IBTS`
	pub const XBTS: u32 = 0x0000_0010;
	/// Decode `0FA6`/`0FA7` as `CMPXCHG`
	pub const CMPXCHG486A: u32 = 0x0000_0020;
	/// Decode some old removed FPU instructions (eg. `FRSTPM`)
	pub const OLD_FPU: u32 = 0x0000_0040;
	/// Decode [`Code::Pcommit`]
	///
	/// [`Code::Pcommit`]: enum.Code.html#variant.Pcommit
	pub const PCOMMIT: u32 = 0x0000_0080;
	/// Decode 286 `LOADALL` (`0F04` and `0F05`)
	pub const LOADALL286: u32 = 0x0000_0100;
	/// Decode [`Code::Loadall386`]
	///
	/// [`Code::Loadall386`]: enum.Code.html#variant.Loadall386
	pub const LOADALL386: u32 = 0x0000_0200;
	/// Decode [`Code::Cl1invmb`]
	///
	/// [`Code::Cl1invmb`]: enum.Code.html#variant.Cl1invmb
	pub const CL1INVMB: u32 = 0x0000_0400;
	/// Decode [`Code::Mov_r32_tr`] and [`Code::Mov_tr_r32`]
	///
	/// [`Code::Mov_r32_tr`]: enum.Code.html#variant.Mov_r32_tr
	/// [`Code::Mov_tr_r32`]: enum.Code.html#variant.Mov_tr_r32
	pub const MOV_TR: u32 = 0x0000_0800;
	/// Decode `JMPE` instructions
	pub const JMPE: u32 = 0x0000_1000;
	/// Don't decode [`Code::Pause`], decode [`Code::Nopd`]/etc instead
	///
	/// [`Code::Pause`]: enum.Code.html#variant.Pause
	/// [`Code::Nopd`]: enum.Code.html#variant.Nopd
	pub const NO_PAUSE: u32 = 0x0000_2000;
	/// Don't decode [`Code::Wbnoinvd`], decode [`Code::Wbinvd`] instead
	///
	/// [`Code::Wbnoinvd`]: enum.Code.html#variant.Wbnoinvd
	/// [`Code::Wbinvd`]: enum.Code.html#variant.Wbinvd
	pub const NO_WBNOINVD: u32 = 0x0000_4000;
	/// Don't decode `LOCK MOV CR0` as `MOV CR8` (AMD)
	pub const NO_LOCK_MOV_CR0: u32 = 0x0000_8000;
	/// Don't decode [`Code::Tzcnt_r32_rm32`]/etc, decode [`Code::Bsf_r32_rm32`]/etc instead
	///
	/// [`Code::Tzcnt_r32_rm32`]: enum.Code.html#variant.Tzcnt_r32_rm32
	/// [`Code::Bsf_r32_rm32`]: enum.Code.html#variant.Bsf_r32_rm32
	pub const NO_MPFX_0FBC: u32 = 0x0001_0000;
	/// Don't decode [`Code::Lzcnt_r32_rm32`]/etc, decode [`Code::Bsr_r32_rm32`]/etc instead
	///
	/// [`Code::Lzcnt_r32_rm32`]: enum.Code.html#variant.Lzcnt_r32_rm32
	/// [`Code::Bsr_r32_rm32`]: enum.Code.html#variant.Bsr_r32_rm32
	pub const NO_MPFX_0FBD: u32 = 0x0002_0000;
	/// Don't decode [`Code::Lahf`] and [`Code::Sahf`] in 64-bit mode
	///
	/// [`Code::Lahf`]: enum.Code.html#variant.Lahf
	/// [`Code::Sahf`]: enum.Code.html#variant.Sahf
	pub const NO_LAHF_SAHF_64: u32 = 0x0004_0000;
}
// GENERATOR-END: DecoderOptions

// GENERATOR-BEGIN: HandlerFlags
// ⚠️This was generated by GENERATOR!🦹‍♂️
pub(crate) struct HandlerFlags;
#[allow(dead_code)]
impl HandlerFlags {
	pub(crate) const NONE: u32 = 0x0000_0000;
	pub(crate) const XACQUIRE: u32 = 0x0000_0001;
	pub(crate) const XRELEASE: u32 = 0x0000_0002;
	pub(crate) const XACQUIRE_XRELEASE_NO_LOCK: u32 = 0x0000_0004;
	pub(crate) const LOCK: u32 = 0x0000_0008;
}
// GENERATOR-END: HandlerFlags

// GENERATOR-BEGIN: StateFlags
// ⚠️This was generated by GENERATOR!🦹‍♂️
pub(crate) struct StateFlags;
#[allow(dead_code)]
impl StateFlags {
	pub(crate) const ENCODING_MASK: u32 = 0x0000_0007;
	pub(crate) const HAS_REX: u32 = 0x0000_0008;
	pub(crate) const B: u32 = 0x0000_0010;
	pub(crate) const Z: u32 = 0x0000_0020;
	pub(crate) const IS_INVALID: u32 = 0x0000_0040;
	pub(crate) const W: u32 = 0x0000_0080;
	pub(crate) const NO_IMM: u32 = 0x0000_0100;
	pub(crate) const ADDR64: u32 = 0x0000_0200;
	pub(crate) const BRANCH_IMM8: u32 = 0x0000_0400;
	pub(crate) const XBEGIN: u32 = 0x0000_0800;
	pub(crate) const LOCK: u32 = 0x0000_1000;
	pub(crate) const ALLOW_LOCK: u32 = 0x0000_2000;
	pub(crate) const NO_MORE_BYTES: u32 = 0x0000_4000;
}
// GENERATOR-END: StateFlags

#[derive(Debug, Default)]
struct State {
	modrm: u32,
	mod_: u32,
	reg: u32,
	rm: u32,

	// ***************************
	// These fields are cleared in decode_out() and should be close so the compiler can optimize clearing them.
	extra_register_base: u32,       // R << 3
	extra_index_register_base: u32, // X << 3
	extra_base_register_base: u32,  // B << 3
	extra_index_register_base_vsib: u32,
	flags: u32, // StateFlags
	mandatory_prefix: u32,
	// ***************************
	vvvv: u32, // V`vvvv. Not stored in inverted form. If 16/32-bit, bits [4:3] are cleared
	aaa: u32,
	extra_register_base_evex: u32,
	extra_base_register_base_evex: u32,
	vector_length: u32,
	operand_size: OpSize,
	address_size: OpSize,
}

impl State {
	#[cfg_attr(has_must_use, must_use)]
	#[inline(always)]
	#[cfg(debug_assertions)]
	fn encoding(&self) -> EncodingKind {
		unsafe { mem::transmute((self.flags & StateFlags::ENCODING_MASK) as u8) }
	}
	#[cfg_attr(has_must_use, must_use)]
	#[inline(always)]
	#[cfg(not(debug_assertions))]
	fn encoding(&self) -> EncodingKind {
		EncodingKind::Legacy
	}
}

/// Decodes 16/32/64-bit x86 instructions
#[derive(Debug)]
pub struct Decoder<'a> {
	ip: u64,

	displ_index: usize,
	prefixes: &'static [u32],
	data: &'a [u8],
	data_ptr: *const u8,
	// This is guaranteed to be >= data_ptr (see the ctor), in other words, it can't overflow to 0
	data_ptr_end: *const u8,
	// Equals to cmp::min(self.data_ptr.offset(IcedConstants::MAX_INSTRUCTION_LENGTH as isize), self.data_ptr_end)
	// and is guaranteed to not overflow
	max_data_ptr: *const u8,
	instr_start_data_ptr: *const u8,
	// These are verified to have exactly 0x100 elements, and they're static, so we don't need fat pointers.
	handlers_xx: *const &'static OpCodeHandler,
	#[cfg(not(feature = "no_vex"))]
	handlers_vex_0fxx: *const &'static OpCodeHandler,
	#[cfg(not(feature = "no_vex"))]
	handlers_vex_0f38xx: *const &'static OpCodeHandler,
	#[cfg(not(feature = "no_vex"))]
	handlers_vex_0f3axx: *const &'static OpCodeHandler,
	#[cfg(not(feature = "no_evex"))]
	handlers_evex_0fxx: *const &'static OpCodeHandler,
	#[cfg(not(feature = "no_evex"))]
	handlers_evex_0f38xx: *const &'static OpCodeHandler,
	#[cfg(not(feature = "no_evex"))]
	handlers_evex_0f3axx: *const &'static OpCodeHandler,
	#[cfg(not(feature = "no_xop"))]
	handlers_xop8: *const &'static OpCodeHandler,
	#[cfg(not(feature = "no_xop"))]
	handlers_xop9: *const &'static OpCodeHandler,
	#[cfg(not(feature = "no_xop"))]
	handlers_xopa: *const &'static OpCodeHandler,
	#[cfg(feature = "no_vex")]
	handlers_vex_0fxx: (),
	#[cfg(feature = "no_vex")]
	handlers_vex_0f38xx: (),
	#[cfg(feature = "no_vex")]
	handlers_vex_0f3axx: (),
	#[cfg(feature = "no_evex")]
	handlers_evex_0fxx: (),
	#[cfg(feature = "no_evex")]
	handlers_evex_0f38xx: (),
	#[cfg(feature = "no_evex")]
	handlers_evex_0f3axx: (),
	#[cfg(feature = "no_xop")]
	handlers_xop8: (),
	#[cfg(feature = "no_xop")]
	handlers_xop9: (),
	#[cfg(feature = "no_xop")]
	handlers_xopa: (),
	state: State,
	// DecoderOptions
	options: u32,
	// All 1s if we should check for invalid instructions, else 0
	invalid_check_mask: u32,
	// StateFlags::W if 64-bit, 0 if 16/32-bit
	is64_mode_and_w: u32,
	default_code_size: CodeSize,
	default_operand_size: OpSize,
	default_address_size: OpSize,
	default_inverted_operand_size: OpSize,
	default_inverted_address_size: OpSize,
	is64_mode: bool,
	bitness: u32,
}

impl<'a> Decoder<'a> {
	/// Creates a decoder
	///
	/// # Panics
	///
	/// Panics if `bitness` is not one of 16, 32, 64.
	///
	/// # Arguments
	///
	/// * `bitness`: 16, 32 or 64
	/// * `data`: Data to decode
	/// * `options`: Decoder options, `0` or eg. `DecoderOptions::NO_INVALID_CHECK | DecoderOptions::AMD_BRANCHES`
	///
	/// # Examples
	///
	/// ```
	/// use iced_x86::*;
	///
	/// // xchg ah,[rdx+rsi+16h]
	/// // xacquire lock add dword ptr [rax],5Ah
	/// // vmovdqu64 zmm18{k3}{z},zmm11
	/// let bytes = b"\x86\x64\x32\x16\xF0\xF2\x83\x00\x5A\x62\xC1\xFE\xCB\x6F\xD3";
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
	/// decoder.set_ip(0x1234_5678);
	///
	/// let instr1 = decoder.decode();
	/// assert_eq!(Code::Xchg_rm8_r8, instr1.code());
	/// assert_eq!(Mnemonic::Xchg, instr1.mnemonic());
	/// assert_eq!(4, instr1.len());
	///
	/// let instr2 = decoder.decode();
	/// assert_eq!(Code::Add_rm32_imm8, instr2.code());
	/// assert_eq!(Mnemonic::Add, instr2.mnemonic());
	/// assert_eq!(5, instr2.len());
	///
	/// let instr3 = decoder.decode();
	/// assert_eq!(Code::EVEX_Vmovdqu64_zmm_k1z_zmmm512, instr3.code());
	/// assert_eq!(Mnemonic::Vmovdqu64, instr3.mnemonic());
	/// assert_eq!(6, instr3.len());
	/// ```
	///
	/// It's sometimes useful to decode some invalid instructions, eg. `lock add esi,ecx`.
	/// Pass in [`DecoderOptions::NO_INVALID_CHECK`] to the constructor and the decoder
	/// will decode some invalid encodings.
	///
	/// [`DecoderOptions::NO_INVALID_CHECK`]: struct.DecoderOptions.html#associatedconstant.NO_INVALID_CHECK
	///
	/// ```
	/// use iced_x86::*;
	///
	/// // lock add esi,ecx   ; lock not allowed
	/// let bytes = b"\xF0\x01\xCE";
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
	/// decoder.set_ip(0x1234_5678);
	/// let instr = decoder.decode();
	/// assert_eq!(Code::INVALID, instr.code());
	///
	/// // We want to decode some instructions with invalid encodings
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NO_INVALID_CHECK);
	/// decoder.set_ip(0x1234_5678);
	/// let instr = decoder.decode();
	/// assert_eq!(Code::Add_rm32_r32, instr.code());
	/// assert!(instr.has_lock_prefix());
	/// ```
	#[cfg_attr(has_must_use, must_use)]
	#[cfg_attr(feature = "cargo-clippy", allow(clippy::missing_inline_in_public_items))]
	#[cfg_attr(feature = "cargo-clippy", allow(clippy::let_unit_value))]
	#[allow(trivial_casts)]
	pub fn new(bitness: u32, data: &'a [u8], options: u32) -> Decoder<'a> {
		let prefixes;
		let is64_mode;
		let default_code_size;
		let default_operand_size;
		let default_inverted_operand_size;
		let default_address_size;
		let default_inverted_address_size;
		match bitness {
			64 => {
				is64_mode = true;
				default_code_size = CodeSize::Code64;
				default_operand_size = OpSize::Size32;
				default_inverted_operand_size = OpSize::Size16;
				default_address_size = OpSize::Size64;
				default_inverted_address_size = OpSize::Size32;
				prefixes = &PREFIXES64;
			}
			32 => {
				is64_mode = false;
				default_code_size = CodeSize::Code32;
				default_operand_size = OpSize::Size32;
				default_inverted_operand_size = OpSize::Size16;
				default_address_size = OpSize::Size32;
				default_inverted_address_size = OpSize::Size16;
				prefixes = &PREFIXES1632;
			}
			16 => {
				is64_mode = false;
				default_code_size = CodeSize::Code16;
				default_operand_size = OpSize::Size16;
				default_inverted_operand_size = OpSize::Size32;
				default_address_size = OpSize::Size16;
				default_inverted_address_size = OpSize::Size32;
				prefixes = &PREFIXES1632;
			}
			_ => panic!(),
		}
		fn get_handlers(handlers: &'static [&'static OpCodeHandler]) -> *const &'static OpCodeHandler {
			debug_assert_eq!(0x100, handlers.len());
			handlers.as_ptr()
		}
		let data_ptr_end: *const u8 = unsafe { data.get_unchecked(data.len()) };
		assert!(data_ptr_end >= data.as_ptr());
		// Verify that max_data_ptr can never overflow and that data_ptr.offset(N) can't overflow
		assert!(unsafe {
			data.as_ptr().offset((data.len() as isize).checked_add(IcedConstants::MAX_INSTRUCTION_LENGTH as isize + 4).unwrap()) >= data.as_ptr()
		});

		let tables = &*TABLES;

		#[cfg(not(feature = "no_vex"))]
		let handlers_vex_0fxx = get_handlers(&tables.handlers_vex_0fxx);
		#[cfg(not(feature = "no_vex"))]
		let handlers_vex_0f38xx = get_handlers(&tables.handlers_vex_0f38xx);
		#[cfg(not(feature = "no_vex"))]
		let handlers_vex_0f3axx = get_handlers(&tables.handlers_vex_0f3axx);
		#[cfg(not(feature = "no_evex"))]
		let handlers_evex_0fxx = get_handlers(&tables.handlers_evex_0fxx);
		#[cfg(not(feature = "no_evex"))]
		let handlers_evex_0f38xx = get_handlers(&tables.handlers_evex_0f38xx);
		#[cfg(not(feature = "no_evex"))]
		let handlers_evex_0f3axx = get_handlers(&tables.handlers_evex_0f3axx);
		#[cfg(not(feature = "no_xop"))]
		let handlers_xop8 = get_handlers(&tables.handlers_xop8);
		#[cfg(not(feature = "no_xop"))]
		let handlers_xop9 = get_handlers(&tables.handlers_xop9);
		#[cfg(not(feature = "no_xop"))]
		let handlers_xopa = get_handlers(&tables.handlers_xopa);

		#[cfg(feature = "no_vex")]
		let handlers_vex_0fxx = ();
		#[cfg(feature = "no_vex")]
		let handlers_vex_0f38xx = ();
		#[cfg(feature = "no_vex")]
		let handlers_vex_0f3axx = ();
		#[cfg(feature = "no_evex")]
		let handlers_evex_0fxx = ();
		#[cfg(feature = "no_evex")]
		let handlers_evex_0f38xx = ();
		#[cfg(feature = "no_evex")]
		let handlers_evex_0f3axx = ();
		#[cfg(feature = "no_xop")]
		let handlers_xop8 = ();
		#[cfg(feature = "no_xop")]
		let handlers_xop9 = ();
		#[cfg(feature = "no_xop")]
		let handlers_xopa = ();

		Decoder {
			ip: 0,
			displ_index: 0,
			prefixes,
			data,
			data_ptr: data.as_ptr(),
			data_ptr_end,
			max_data_ptr: data.as_ptr(),
			instr_start_data_ptr: data.as_ptr(),
			handlers_xx: get_handlers(&tables.handlers_xx),
			handlers_vex_0fxx,
			handlers_vex_0f38xx,
			handlers_vex_0f3axx,
			handlers_evex_0fxx,
			handlers_evex_0f38xx,
			handlers_evex_0f3axx,
			handlers_xop8,
			handlers_xop9,
			handlers_xopa,
			state: State::default(),
			options,
			invalid_check_mask: if (options & DecoderOptions::NO_INVALID_CHECK) == 0 { u32::MAX } else { 0 },
			is64_mode_and_w: if is64_mode { StateFlags::W } else { 0 },
			default_code_size,
			default_operand_size,
			default_inverted_operand_size,
			default_address_size,
			default_inverted_address_size,
			is64_mode,
			bitness,
		}
	}

	/// Gets the current `IP`/`EIP`/`RIP` value, see also [`position()`]
	///
	/// [`position()`]: #method.position
	#[cfg_attr(has_must_use, must_use)]
	#[inline]
	pub fn ip(&self) -> u64 {
		self.ip
	}

	/// Sets the current `IP`/`EIP`/`RIP` value, see also [`set_position()`]
	///
	/// [`set_position()`]: #method.set_position
	///
	/// # Arguments
	///
	/// * `new_value`: New IP
	#[inline]
	pub fn set_ip(&mut self, new_value: u64) {
		self.ip = new_value;
	}

	/// Gets the bitness (16, 32 or 64)
	#[cfg_attr(has_must_use, must_use)]
	#[inline]
	pub fn bitness(&self) -> u32 {
		self.bitness
	}

	/// Gets the max value that can be passed to [`set_position()`]. This is the size of the data that gets
	/// decoded to instructions and it's the length of the slice that was passed to the constructor.
	///
	/// [`set_position()`]: #method.set_position
	#[cfg_attr(has_must_use, must_use)]
	#[inline]
	pub fn max_position(&self) -> usize {
		self.data.len()
	}

	/// Gets the current data position. This value is always <= [`max_position()`].
	/// When [`position()`] == [`max_position()`], it's not possible to decode more
	/// instructions and [`can_decode()`] returns `false`.
	///
	/// [`max_position()`]: #method.max_position
	/// [`position()`]: #method.position
	/// [`can_decode()`]: #method.can_decode
	#[cfg_attr(has_must_use, must_use)]
	#[inline]
	pub fn position(&self) -> usize {
		self.data_ptr as usize - self.data.as_ptr() as usize
	}

	/// Sets the current data position, which is the index into the data passed to the constructor.
	/// This value is always <= [`max_position()`]
	///
	/// [`max_position()`]: #method.max_position
	///
	/// # Panics
	///
	/// Panics if the new position is invalid.
	///
	/// # Arguments
	///
	/// * `new_pos`: New position and must be <= [`max_position()`]
	///
	/// # Examples
	///
	/// ```
	/// use iced_x86::*;
	///
	/// // nop and pause
	/// let bytes = b"\x90\xF3\x90";
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
	/// decoder.set_ip(0x1234_5678);
	///
	/// assert_eq!(0, decoder.position());
	/// assert_eq!(3, decoder.max_position());
	/// let instr = decoder.decode();
	/// assert_eq!(1, decoder.position());
	/// assert_eq!(Code::Nopd, instr.code());
	///
	/// let instr = decoder.decode();
	/// assert_eq!(3, decoder.position());
	/// assert_eq!(Code::Pause, instr.code());
	///
	/// // Start all over again
	/// decoder.set_position(0);
	/// assert_eq!(0, decoder.position());
	/// assert_eq!(Code::Nopd, decoder.decode().code());
	/// assert_eq!(Code::Pause, decoder.decode().code());
	/// assert_eq!(3, decoder.position());
	/// ```
	#[inline]
	pub fn set_position(&mut self, new_pos: usize) {
		assert!(new_pos <= self.data.len());
		self.data_ptr = unsafe { self.data.get_unchecked(new_pos) };
	}

	/// Returns `true` if there's at least one more byte to decode. It doesn't verify that the
	/// next instruction is valid, it only checks if there's at least one more byte to read.
	/// See also [`position()`] and [`max_position()`]
	///
	/// It's not required to call this method. If this method returns `false`, then [`decode_out()`]
	/// and [`decode()`] will return an instruction whose [`code()`] == [`Code::INVALID`].
	///
	/// [`position()`]: #method.position
	/// [`max_position()`]: #method.max_position
	/// [`decode_out()`]: #method.decode_out
	/// [`decode()`]: #method.decode
	/// [`code()`]: struct.Instruction.html#method.code
	/// [`Code::INVALID`]: enum.Code.html#variant.INVALID
	///
	/// # Examples
	///
	/// ```
	/// use iced_x86::*;
	///
	/// // nop and an incomplete instruction
	/// let bytes = b"\x90\xF3\x0F";
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
	/// decoder.set_ip(0x1234_5678);
	///
	/// // 3 bytes left to read
	/// assert!(decoder.can_decode());
	/// let instr = decoder.decode();
	/// assert_eq!(Code::Nopd, instr.code());
	///
	/// // 2 bytes left to read
	/// assert!(decoder.can_decode());
	/// let instr = decoder.decode();
	/// // Not enough bytes left to decode a full instruction
	/// assert_eq!(Code::INVALID, instr.code());
	///
	/// // 0 bytes left to read
	/// assert!(!decoder.can_decode());
	/// ```
	#[cfg_attr(has_must_use, must_use)]
	#[inline]
	pub fn can_decode(&self) -> bool {
		self.data_ptr != self.data_ptr_end
	}

	/// Returns an iterator that borrows this instance to decode instructions until there's
	/// no more data to decode, i.e., until [`can_decode()`] returns `false`.
	///
	/// [`can_decode()`]: #method.can_decode
	///
	/// # Examples
	///
	/// ```
	/// use iced_x86::*;
	///
	/// // nop and pause
	/// let bytes = b"\x90\xF3\x90";
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
	/// decoder.set_ip(0x1234_5678);
	///
	/// let mut iter = decoder.iter();
	/// assert_eq!(Code::Nopd, iter.next().unwrap().code());
	/// assert_eq!(Code::Pause, iter.next().unwrap().code());
	/// assert!(iter.next().is_none());
	/// ```
	///
	/// For loop
	///
	/// ```
	/// use iced_x86::*;
	///
	/// let bytes = b"\x90\xF3\x90";
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
	/// decoder.set_ip(0x1234_5678);
	///
	/// for instr in &mut decoder { // or decoder.iter()
	///     println!("code: {:?}", instr.code());
	/// }
	/// ```
	#[inline]
	pub fn iter<'b>(&'b mut self) -> DecoderIter<'a, 'b> {
		DecoderIter { decoder: self }
	}

	#[cfg_attr(has_must_use, must_use)]
	pub(self) fn read_u8(&mut self) -> usize {
		unsafe {
			let data_ptr = self.data_ptr;
			if data_ptr < self.max_data_ptr {
				let result = ptr::read(data_ptr) as usize;
				self.data_ptr = data_ptr.offset(1);
				result
			} else {
				self.state.flags |= StateFlags::IS_INVALID | StateFlags::NO_MORE_BYTES;
				0
			}
		}
	}

	#[cfg_attr(has_must_use, must_use)]
	pub(self) fn read_u16(&mut self) -> usize {
		unsafe {
			let data_ptr = self.data_ptr;
			if data_ptr.offset(1) < self.max_data_ptr {
				#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
				let result = u16::from_le(ptr::read_unaligned(data_ptr as *const u16)) as usize;
				self.data_ptr = data_ptr.offset(2);
				result
			} else {
				self.state.flags |= StateFlags::IS_INVALID | StateFlags::NO_MORE_BYTES;
				0
			}
		}
	}

	#[cfg_attr(has_must_use, must_use)]
	pub(self) fn read_u32(&mut self) -> usize {
		// What I really wanted to do was: (this saves one instruction)
		//		const N: isize = 4;
		//		let data_ptr = self.data_ptr.offset(N);
		//		if data_ptr <= self.max_data_ptr {
		//		+ update the code below
		// but the compiler generates worse code when '<=' is used instead of '<'.
		// Instead of jumping to the error code at the end of the method, it now
		// jumps to the likely path.
		// core::intrinsics::likely() can only be used with nightly rustc builds.
		// https://github.com/rust-lang/rust/issues/26179

		unsafe {
			let data_ptr = self.data_ptr;
			if data_ptr.offset(3) < self.max_data_ptr {
				#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
				let result = u32::from_le(ptr::read_unaligned(data_ptr as *const u32)) as usize;
				self.data_ptr = data_ptr.offset(4);
				result
			} else {
				self.state.flags |= StateFlags::IS_INVALID | StateFlags::NO_MORE_BYTES;
				0
			}
		}
	}

	/// This method can be called after calling [`decode()`] and [`decode_out()`] to check if the
	/// decoded instruction is invalid because there's no more bytes left or because of bad input data.
	///
	/// [`decode()`]: #method.decode
	/// [`decode_out()`]: #method.decode_out
	#[cfg_attr(has_must_use, must_use)]
	#[inline]
	pub fn invalid_no_more_bytes(&self) -> bool {
		(self.state.flags & StateFlags::NO_MORE_BYTES) != 0
	}

	/// Decodes and returns the next instruction, see also [`decode_out(&mut Instruction)`]
	/// which avoids copying the decoded instruction to the caller's return variable.
	/// See also [`invalid_no_more_bytes()`].
	///
	/// [`decode_out(&mut Instruction)`]: #method.decode_out
	/// [`invalid_no_more_bytes()`]: #method.invalid_no_more_bytes
	///
	/// # Examples
	///
	/// ```
	/// use iced_x86::*;
	///
	/// // xrelease lock add [rax],ebx
	/// let bytes = b"\xF0\xF3\x01\x18";
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
	/// decoder.set_ip(0x1234_5678);
	/// let instr = decoder.decode();
	///
	/// assert_eq!(Code::Add_rm32_r32, instr.code());
	/// assert_eq!(Mnemonic::Add, instr.mnemonic());
	/// assert_eq!(4, instr.len());
	/// assert_eq!(2, instr.op_count());
	///
	/// assert_eq!(OpKind::Memory, instr.op0_kind());
	/// assert_eq!(Register::RAX, instr.memory_base());
	/// assert_eq!(Register::None, instr.memory_index());
	/// assert_eq!(1, instr.memory_index_scale());
	/// assert_eq!(0, instr.memory_displacement());
	/// assert_eq!(Register::DS, instr.memory_segment());
	/// assert_eq!(Register::None, instr.segment_prefix());
	/// assert_eq!(MemorySize::UInt32, instr.memory_size());
	///
	/// assert_eq!(OpKind::Register, instr.op1_kind());
	/// assert_eq!(Register::EBX, instr.op1_register());
	///
	/// assert!(instr.has_lock_prefix());
	/// assert!(instr.has_xrelease_prefix());
	/// ```
	#[cfg_attr(has_must_use, must_use)]
	#[cfg(has_maybe_uninit)]
	#[inline]
	pub fn decode(&mut self) -> Instruction {
		// Safe, decode_out() initializes the whole thing
		let mut instruction = unsafe { mem::MaybeUninit::uninit().assume_init() };
		self.decode_out(&mut instruction);
		instruction
	}

	/// Decodes and returns the next instruction, see also [`decode_out(&mut Instruction)`]
	/// which avoids copying the decoded instruction to the caller's return variable.
	/// See also [`invalid_no_more_bytes()`].
	///
	/// [`decode_out(&mut Instruction)`]: #method.decode_out
	/// [`invalid_no_more_bytes()`]: #method.invalid_no_more_bytes
	///
	/// # Examples
	///
	/// ```
	/// use iced_x86::*;
	///
	/// // xrelease lock add [rax],ebx
	/// let bytes = b"\xF0\xF3\x01\x18";
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
	/// decoder.set_ip(0x1234_5678);
	/// let instr = decoder.decode();
	///
	/// assert_eq!(Code::Add_rm32_r32, instr.code());
	/// assert_eq!(Mnemonic::Add, instr.mnemonic());
	/// assert_eq!(4, instr.len());
	/// assert_eq!(2, instr.op_count());
	///
	/// assert_eq!(OpKind::Memory, instr.op0_kind());
	/// assert_eq!(Register::RAX, instr.memory_base());
	/// assert_eq!(Register::None, instr.memory_index());
	/// assert_eq!(1, instr.memory_index_scale());
	/// assert_eq!(0, instr.memory_displacement());
	/// assert_eq!(Register::DS, instr.memory_segment());
	/// assert_eq!(Register::None, instr.segment_prefix());
	/// assert_eq!(MemorySize::UInt32, instr.memory_size());
	///
	/// assert_eq!(OpKind::Register, instr.op1_kind());
	/// assert_eq!(Register::EBX, instr.op1_register());
	///
	/// assert!(instr.has_lock_prefix());
	/// assert!(instr.has_xrelease_prefix());
	/// ```
	#[cfg_attr(has_must_use, must_use)]
	#[allow(deprecated_in_future)]
	#[cfg(not(has_maybe_uninit))]
	#[inline]
	pub fn decode(&mut self) -> Instruction {
		// Safe, decode_out() initializes the whole thing
		let mut instruction = unsafe { mem::uninitialized() };
		self.decode_out(&mut instruction);
		instruction
	}

	/// Decodes the next instruction. The difference between this method and [`decode()`] is that this
	/// method doesn't need to copy the result to the caller's return variable (saves 32-bytes of copying).
	/// See also [`invalid_no_more_bytes()`].
	///
	/// [`decode()`]: #method.decode
	/// [`invalid_no_more_bytes()`]: #method.invalid_no_more_bytes
	///
	/// # Arguments
	///
	/// * `instruction`: Updated with the decoded instruction. All fields are initialized (it's an `out` argument)
	///
	/// # Examples
	///
	/// ```
	/// use iced_x86::*;
	///
	/// // xrelease lock add [rax],ebx
	/// let bytes = b"\xF0\xF3\x01\x18";
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
	/// decoder.set_ip(0x1234_5678);
	/// // or use core::mem::MaybeUninit:
	/// //    let mut instr = unsafe { core::mem::MaybeUninit::uninit().assume_init() };
	/// // to not clear `instr` more than once (`decode_out()` initializes all its fields).
	/// let mut instr = Instruction::default();
	/// decoder.decode_out(&mut instr);
	///
	/// assert_eq!(Code::Add_rm32_r32, instr.code());
	/// assert_eq!(Mnemonic::Add, instr.mnemonic());
	/// assert_eq!(4, instr.len());
	/// assert_eq!(2, instr.op_count());
	///
	/// assert_eq!(OpKind::Memory, instr.op0_kind());
	/// assert_eq!(Register::RAX, instr.memory_base());
	/// assert_eq!(Register::None, instr.memory_index());
	/// assert_eq!(1, instr.memory_index_scale());
	/// assert_eq!(0, instr.memory_displacement());
	/// assert_eq!(Register::DS, instr.memory_segment());
	/// assert_eq!(Register::None, instr.segment_prefix());
	/// assert_eq!(MemorySize::UInt32, instr.memory_size());
	///
	/// assert_eq!(OpKind::Register, instr.op1_kind());
	/// assert_eq!(Register::EBX, instr.op1_register());
	///
	/// assert!(instr.has_lock_prefix());
	/// assert!(instr.has_xrelease_prefix());
	/// ```
	#[cfg_attr(feature = "cargo-clippy", allow(clippy::missing_inline_in_public_items))]
	pub fn decode_out(&mut self, instruction: &mut Instruction) {
		*instruction = Instruction::default();

		self.state.extra_register_base = 0;
		self.state.extra_index_register_base = 0;
		self.state.extra_base_register_base = 0;
		self.state.extra_index_register_base_vsib = 0;
		self.state.flags = 0;
		self.state.mandatory_prefix = 0;

		self.state.operand_size = self.default_operand_size;
		self.state.address_size = self.default_address_size;

		let data_ptr = self.data_ptr;
		self.instr_start_data_ptr = data_ptr;
		// The ctor has verified that the two expressions used in min() don't overflow and are >= data_ptr.
		self.max_data_ptr = unsafe { cmp::min(data_ptr.offset(IcedConstants::MAX_INSTRUCTION_LENGTH as isize), self.data_ptr_end) };

		let mut default_ds_segment = Register::DS;
		let mut rex_prefix: usize = 0;
		let mut b;
		loop {
			b = self.read_u8();
			if unsafe { (((*self.prefixes.get_unchecked(b / 32)) >> (b & 31)) & 1) == 0 } {
				break;
			}

			match b {
				0x26 => {
					if !self.is64_mode || default_ds_segment < Register::FS {
						instruction.set_segment_prefix(Register::ES);
						default_ds_segment = Register::ES;
					}
					rex_prefix = 0;
				}
				0x2E => {
					if !self.is64_mode || default_ds_segment < Register::FS {
						instruction.set_segment_prefix(Register::CS);
						default_ds_segment = Register::CS;
					}
					rex_prefix = 0;
				}
				0x36 => {
					if !self.is64_mode || default_ds_segment < Register::FS {
						instruction.set_segment_prefix(Register::SS);
						default_ds_segment = Register::SS;
					}
					rex_prefix = 0;
				}
				0x3E => {
					if !self.is64_mode || default_ds_segment < Register::FS {
						instruction.set_segment_prefix(Register::DS);
						default_ds_segment = Register::DS;
					}
					rex_prefix = 0;
				}
				0x64 => {
					instruction.set_segment_prefix(Register::FS);
					default_ds_segment = Register::FS;
					rex_prefix = 0;
				}
				0x65 => {
					instruction.set_segment_prefix(Register::GS);
					default_ds_segment = Register::GS;
					rex_prefix = 0;
				}
				0x66 => {
					self.state.operand_size = self.default_inverted_operand_size;
					if self.state.mandatory_prefix == MandatoryPrefixByte::None as u32 {
						self.state.mandatory_prefix = MandatoryPrefixByte::P66 as u32;
					}
					rex_prefix = 0;
				}
				0x67 => {
					self.state.address_size = self.default_inverted_address_size;
					rex_prefix = 0;
				}
				0xF0 => {
					super::instruction_internal::internal_set_has_lock_prefix(instruction);
					self.state.flags |= StateFlags::LOCK;
					rex_prefix = 0;
				}
				0xF2 => {
					super::instruction_internal::internal_set_has_repne_prefix(instruction);
					self.state.mandatory_prefix = MandatoryPrefixByte::PF2 as u32;
					rex_prefix = 0;
				}
				0xF3 => {
					super::instruction_internal::internal_set_has_repe_prefix(instruction);
					self.state.mandatory_prefix = MandatoryPrefixByte::PF3 as u32;
					rex_prefix = 0;
				}
				_ => {
					debug_assert!(self.is64_mode);
					debug_assert!(0x40 <= b && b <= 0x4F);
					rex_prefix = b;
				}
			}
		}
		if rex_prefix != 0 {
			if (rex_prefix & 8) != 0 {
				self.state.operand_size = OpSize::Size64;
				self.state.flags |= StateFlags::HAS_REX | StateFlags::W;
			} else {
				self.state.flags |= StateFlags::HAS_REX;
			}
			self.state.extra_register_base = (rex_prefix as u32 & 4) << 1;
			self.state.extra_index_register_base = (rex_prefix as u32 & 2) << 2;
			self.state.extra_base_register_base = (rex_prefix as u32 & 1) << 3;
		}
		// Temp needed if rustc < 1.36.0 (2015 edition)
		let tmp_handler = unsafe { *self.handlers_xx.offset(b as isize) };
		self.decode_table2(tmp_handler, instruction);
		let flags = self.state.flags;
		if (flags & (StateFlags::IS_INVALID | StateFlags::LOCK)) != 0 {
			if (flags & StateFlags::IS_INVALID) != 0
				|| (((flags & (StateFlags::LOCK | StateFlags::ALLOW_LOCK)) & self.invalid_check_mask) == StateFlags::LOCK)
			{
				*instruction = Instruction::default();
				const_assert_eq!(0, Code::INVALID as u32);
				//super::instruction_internal::internal_set_code(instruction, Code::INVALID);
				if (flags & StateFlags::NO_MORE_BYTES) != 0 {
					self.data_ptr = self.max_data_ptr;
				}
			}
		}
		super::instruction_internal::internal_set_code_size(instruction, self.default_code_size);
		debug_assert_eq!(self.instr_start_data_ptr, data_ptr);
		let instr_len = self.data_ptr as usize - data_ptr as usize;
		debug_assert!(instr_len <= IcedConstants::MAX_INSTRUCTION_LENGTH); // Could be 0 if there were no bytes available
		super::instruction_internal::internal_set_len(instruction, instr_len as u32);

		let ip = self.ip.wrapping_add(instr_len as u64);
		self.ip = ip;
		instruction.set_next_ip(ip);
	}

	#[cfg_attr(has_must_use, must_use)]
	#[inline]
	pub(self) fn current_ip32(&self) -> u32 {
		debug_assert!(self.instr_start_data_ptr <= self.data_ptr);
		debug_assert!(self.data_ptr as usize - self.instr_start_data_ptr as usize <= IcedConstants::MAX_INSTRUCTION_LENGTH);
		((self.data_ptr as usize - self.instr_start_data_ptr as usize) as u32).wrapping_add(self.ip as u32)
	}

	#[cfg_attr(has_must_use, must_use)]
	#[inline]
	pub(self) fn current_ip64(&self) -> u64 {
		debug_assert!(self.instr_start_data_ptr <= self.data_ptr);
		debug_assert!(self.data_ptr as usize - self.instr_start_data_ptr as usize <= IcedConstants::MAX_INSTRUCTION_LENGTH);
		((self.data_ptr as usize - self.instr_start_data_ptr as usize) as u64).wrapping_add(self.ip)
	}

	// It's not possible to use 'as u32' on the left side in a match arm
	const P66: u32 = MandatoryPrefixByte::P66 as u32;
	const PF3: u32 = MandatoryPrefixByte::PF3 as u32;
	const PF2: u32 = MandatoryPrefixByte::PF2 as u32;
	pub(self) fn clear_mandatory_prefix(&mut self, instruction: &mut Instruction) {
		debug_assert_eq!(EncodingKind::Legacy, self.state.encoding());
		match self.state.mandatory_prefix {
			Decoder::P66 => self.state.operand_size = self.default_operand_size,
			Decoder::PF3 => instruction_internal::internal_clear_has_repe_prefix(instruction),
			Decoder::PF2 => instruction_internal::internal_clear_has_repne_prefix(instruction),
			_ => {}
		}
	}

	#[inline(always)]
	pub(self) fn set_xacquire_xrelease(&mut self, instruction: &mut Instruction, flags: u32) {
		if (flags & HandlerFlags::XACQUIRE_XRELEASE_NO_LOCK) != 0 || instruction.has_lock_prefix() {
			self.set_xacquire_xrelease_core(instruction, flags);
		}
	}

	fn set_xacquire_xrelease_core(&mut self, instruction: &mut Instruction, flags: u32) {
		debug_assert!(!((flags & HandlerFlags::XACQUIRE_XRELEASE_NO_LOCK) == 0 && !instruction.has_lock_prefix()));
		match self.state.mandatory_prefix {
			Decoder::PF2 => {
				if (flags & HandlerFlags::XACQUIRE) != 0 {
					self.clear_mandatory_prefix_f2(instruction);
					super::instruction_internal::internal_set_has_xacquire_prefix(instruction);
				}
			}
			Decoder::PF3 => {
				if (flags & HandlerFlags::XRELEASE) != 0 {
					self.clear_mandatory_prefix_f3(instruction);
					super::instruction_internal::internal_set_has_xrelease_prefix(instruction);
				}
			}
			_ => {}
		}
	}

	#[inline]
	fn clear_mandatory_prefix_f3(&self, instruction: &mut Instruction) {
		debug_assert_eq!(EncodingKind::Legacy, self.state.encoding());
		debug_assert_eq!(MandatoryPrefixByte::PF3 as u32, self.state.mandatory_prefix);
		super::instruction_internal::internal_clear_has_repe_prefix(instruction);
	}

	#[inline]
	fn clear_mandatory_prefix_f2(&self, instruction: &mut Instruction) {
		debug_assert_eq!(EncodingKind::Legacy, self.state.encoding());
		debug_assert_eq!(MandatoryPrefixByte::PF2 as u32, self.state.mandatory_prefix);
		super::instruction_internal::internal_clear_has_repne_prefix(instruction);
	}

	#[inline]
	pub(self) fn set_invalid_instruction(&mut self) {
		self.state.flags |= StateFlags::IS_INVALID;
	}

	#[inline(always)]
	pub(self) fn decode_table(&mut self, table: *const &OpCodeHandler, instruction: &mut Instruction) {
		let b = self.read_u8();
		self.decode_table2(unsafe { *table.offset(b as isize) }, instruction);
	}

	#[inline(always)]
	fn decode_table2(&mut self, handler: &OpCodeHandler, instruction: &mut Instruction) {
		if handler.has_modrm {
			let m = self.read_u8() as u32;
			self.state.modrm = m;
			self.state.mod_ = m >> 6;
			self.state.reg = (m >> 3) & 7;
			self.state.rm = m & 7;
		}
		(handler.decode)(handler, self, instruction);
	}

	#[inline(always)]
	pub(self) fn read_modrm(&mut self) {
		let m = self.read_u8() as u32;
		self.state.modrm = m;
		self.state.mod_ = m >> 6;
		self.state.reg = (m >> 3) & 7;
		self.state.rm = m & 7;
	}

	#[cfg(feature = "no_vex")]
	pub(self) fn vex2(&mut self, _instruction: &mut Instruction) {
		self.set_invalid_instruction();
	}

	#[cfg(not(feature = "no_vex"))]
	pub(self) fn vex2(&mut self, instruction: &mut Instruction) {
		if (((self.state.flags & StateFlags::HAS_REX) | self.state.mandatory_prefix) & self.invalid_check_mask) != 0 {
			self.set_invalid_instruction();
		}
		// Undo what decode_out() did if it got a REX prefix
		self.state.flags &= !StateFlags::W;
		self.state.extra_index_register_base = 0;
		self.state.extra_base_register_base = 0;

		if cfg!(debug_assertions) {
			self.state.flags |= EncodingKind::VEX as u32;
		}

		let b = self.state.modrm;
		if self.is64_mode {
			self.state.extra_register_base = ((b & 0x80) >> 4) ^ 8;
		}
		// Bit 6 can only be 1 if it's 16/32-bit mode, so we don't need to change the mask
		self.state.vvvv = (!b >> 3) & 0x0F;

		const_assert_eq!(0, VectorLength::L128 as u32);
		const_assert_eq!(1, VectorLength::L256 as u32);
		self.state.vector_length = (b >> 2) & 1;

		const_assert_eq!(0, MandatoryPrefixByte::None as u32);
		const_assert_eq!(1, MandatoryPrefixByte::P66 as u32);
		const_assert_eq!(2, MandatoryPrefixByte::PF3 as u32);
		const_assert_eq!(3, MandatoryPrefixByte::PF2 as u32);
		self.state.mandatory_prefix = b & 3;

		// Temp needed if rustc < 1.36.0 (2015 edition)
		let tmp_handlers = self.handlers_vex_0fxx;
		self.decode_table(tmp_handlers, instruction);
	}

	#[cfg(feature = "no_vex")]
	pub(self) fn vex3(&mut self, _instruction: &mut Instruction) {
		self.set_invalid_instruction();
	}

	#[cfg(not(feature = "no_vex"))]
	pub(self) fn vex3(&mut self, instruction: &mut Instruction) {
		if (((self.state.flags & StateFlags::HAS_REX) | self.state.mandatory_prefix) & self.invalid_check_mask) != 0 {
			self.set_invalid_instruction();
		}
		// Undo what decode_out() did if it got a REX prefix
		self.state.flags &= !StateFlags::W;

		if cfg!(debug_assertions) {
			self.state.flags |= EncodingKind::VEX as u32;
		}

		let b1 = self.state.modrm;
		let b2 = self.read_u8() as u32;

		const_assert_eq!(0x80, StateFlags::W);
		self.state.flags |= b2 & 0x80;

		const_assert_eq!(0, VectorLength::L128 as u32);
		const_assert_eq!(1, VectorLength::L256 as u32);
		self.state.vector_length = (b2 >> 2) & 1;

		const_assert_eq!(0, MandatoryPrefixByte::None as u32);
		const_assert_eq!(1, MandatoryPrefixByte::P66 as u32);
		const_assert_eq!(2, MandatoryPrefixByte::PF3 as u32);
		const_assert_eq!(3, MandatoryPrefixByte::PF2 as u32);
		self.state.mandatory_prefix = b2 & 3;

		if self.is64_mode {
			self.state.vvvv = (!b2 >> 3) & 0x0F;
			let b1x = !b1;
			self.state.extra_register_base = (b1x >> 4) & 8;
			self.state.extra_index_register_base = (b1x >> 3) & 8;
			self.state.extra_base_register_base = (b1x >> 2) & 8;
		} else {
			self.state.vvvv = (!b2 >> 3) & 0x07;
		}

		let table = match b1 & 0x1F {
			1 => self.handlers_vex_0fxx,
			2 => self.handlers_vex_0f38xx,
			3 => self.handlers_vex_0f3axx,
			_ => {
				self.set_invalid_instruction();
				return;
			}
		};
		self.decode_table(table, instruction);
	}

	#[cfg(feature = "no_xop")]
	pub(self) fn xop(&mut self, _instruction: &mut Instruction) {
		self.set_invalid_instruction();
	}

	#[cfg(not(feature = "no_xop"))]
	pub(self) fn xop(&mut self, instruction: &mut Instruction) {
		if (((self.state.flags & StateFlags::HAS_REX) | self.state.mandatory_prefix) & self.invalid_check_mask) != 0 {
			self.set_invalid_instruction();
		}
		// Undo what decode_out() did if it got a REX prefix
		self.state.flags &= !StateFlags::W;

		if cfg!(debug_assertions) {
			self.state.flags |= EncodingKind::XOP as u32;
		}

		let b1 = self.state.modrm;
		let b2 = self.read_u8() as u32;

		const_assert_eq!(0x80, StateFlags::W);
		self.state.flags |= b2 & 0x80;

		const_assert_eq!(0, VectorLength::L128 as u32);
		const_assert_eq!(1, VectorLength::L256 as u32);
		self.state.vector_length = (b2 >> 2) & 1;

		const_assert_eq!(0, MandatoryPrefixByte::None as u32);
		const_assert_eq!(1, MandatoryPrefixByte::P66 as u32);
		const_assert_eq!(2, MandatoryPrefixByte::PF3 as u32);
		const_assert_eq!(3, MandatoryPrefixByte::PF2 as u32);
		self.state.mandatory_prefix = b2 & 3;

		if self.is64_mode {
			self.state.vvvv = (!b2 >> 3) & 0x0F;
			let b1x = !b1;
			self.state.extra_register_base = (b1x >> 4) & 8;
			self.state.extra_index_register_base = (b1x >> 3) & 8;
			self.state.extra_base_register_base = (b1x >> 2) & 8;
		} else {
			self.state.vvvv = (!b2 >> 3) & 0x07;
		}

		let table = match b1 & 0x1F {
			8 => self.handlers_xop8,
			9 => self.handlers_xop9,
			10 => self.handlers_xopa,
			_ => {
				self.set_invalid_instruction();
				return;
			}
		};
		self.decode_table(table, instruction);
	}

	#[cfg(feature = "no_evex")]
	pub(self) fn evex_mvex(&mut self, _instruction: &mut Instruction) {
		self.set_invalid_instruction();
	}

	#[cfg(not(feature = "no_evex"))]
	pub(self) fn evex_mvex(&mut self, instruction: &mut Instruction) {
		if (((self.state.flags & StateFlags::HAS_REX) | self.state.mandatory_prefix) & self.invalid_check_mask) != 0 {
			self.set_invalid_instruction();
		}
		// Undo what decode_out() did if it got a REX prefix
		self.state.flags &= !StateFlags::W;

		let p0 = self.state.modrm;
		let mut p1 = self.read_u16() as u32;
		let p2 = p1 >> 8;
		p1 = p1 as u8 as u32;

		if (p1 & 4) != 0 {
			if (p0 & 0x0C) == 0 {
				if cfg!(debug_assertions) {
					self.state.flags |= EncodingKind::EVEX as u32;
				}

				const_assert_eq!(0, MandatoryPrefixByte::None as u32);
				const_assert_eq!(1, MandatoryPrefixByte::P66 as u32);
				const_assert_eq!(2, MandatoryPrefixByte::PF3 as u32);
				const_assert_eq!(3, MandatoryPrefixByte::PF2 as u32);
				self.state.mandatory_prefix = p1 & 3;

				const_assert_eq!(0x80, StateFlags::W);
				self.state.flags |= p1 & 0x80;

				let aaa = p2 & 7;
				self.state.aaa = aaa;
				super::instruction_internal::internal_set_op_mask(instruction, aaa);
				if (p2 & 0x80) != 0 {
					// invalid if aaa == 0 and if we check for invalid instructions (it's all 1s)
					if (aaa ^ self.invalid_check_mask) == u32::MAX {
						self.set_invalid_instruction();
					}
					self.state.flags |= StateFlags::Z;
					super::instruction_internal::internal_set_zeroing_masking(instruction);
				}

				const_assert_eq!(0x10, StateFlags::B);
				self.state.flags |= p2 & 0x10;

				const_assert_eq!(0, VectorLength::L128 as u32);
				const_assert_eq!(1, VectorLength::L256 as u32);
				const_assert_eq!(2, VectorLength::L512 as u32);
				const_assert_eq!(3, VectorLength::Unknown as u32);
				self.state.vector_length = (p2 >> 5) & 3;

				if self.is64_mode {
					self.state.vvvv = (!p1 >> 3) & 0x0F;
					let tmp = (!p2 & 8) << 1;
					self.state.vvvv += tmp;
					self.state.extra_index_register_base_vsib = tmp;
					let p0x = !p0;
					self.state.extra_register_base = (p0x >> 4) & 8;
					self.state.extra_index_register_base = (p0x & 0x40) >> 3;
					self.state.extra_base_register_base_evex = (p0x & 0x40) >> 2;
					self.state.extra_base_register_base = (p0x >> 2) & 8;
					self.state.extra_register_base_evex = p0x & 0x10;
				} else {
					self.state.vvvv = (!p1 >> 3) & 0x07;
				}

				let table = match p0 & 3 {
					1 => self.handlers_evex_0fxx,
					2 => self.handlers_evex_0f38xx,
					3 => self.handlers_evex_0f3axx,
					_ => {
						self.set_invalid_instruction();
						return;
					}
				};
				let handler = unsafe { *table.offset(self.read_u8() as isize) };
				debug_assert!(handler.has_modrm);
				let m = self.read_u8() as u32;
				self.state.modrm = m;
				self.state.mod_ = m >> 6;
				self.state.reg = (m >> 3) & 7;
				self.state.rm = m & 7;
				// Invalid if LL=3 and (mem or (reg and no rc))
				if (self.invalid_check_mask & self.state.vector_length) == 3 && (m < 0xC0 || (self.state.flags & StateFlags::B) == 0) {
					self.set_invalid_instruction();
				}
				(handler.decode)(handler, self, instruction);
			} else {
				self.set_invalid_instruction();
			}
		} else {
			self.set_invalid_instruction();
		}
	}

	#[cfg_attr(has_must_use, must_use)]
	#[inline(always)]
	pub(self) fn read_op_seg_reg(&mut self) -> u32 {
		let reg = self.state.reg;
		if reg < 6 {
			Register::ES as u32 + reg
		} else {
			self.state.flags |= StateFlags::IS_INVALID;
			Register::None as u32
		}
	}

	#[inline(always)]
	pub(self) fn read_op_mem(&mut self, instruction: &mut Instruction) {
		debug_assert_ne!(EncodingKind::EVEX, self.state.encoding());
		if self.state.address_size == OpSize::Size64 {
			let _ = self.read_op_mem_32_or_64(instruction, Register::RAX, Register::RAX, TupleType::None, false);
		} else if self.state.address_size == OpSize::Size32 {
			let _ = self.read_op_mem_32_or_64(instruction, Register::EAX, Register::EAX, TupleType::None, false);
		} else {
			self.read_op_mem_16(instruction, TupleType::None);
		}
	}

	// All MPX instructions in 64-bit mode force 64-bit addressing, and
	// all MPX instructions in 16/32-bit mode require 32-bit addressing
	// (see SDM Vol 1, 17.5.1 Intel MPX and Operating Modes)
	#[inline(always)]
	pub(self) fn read_op_mem_mpx(&mut self, instruction: &mut Instruction) {
		debug_assert_ne!(EncodingKind::EVEX, self.state.encoding());
		if self.is64_mode {
			self.state.address_size = OpSize::Size64;
			let _ = self.read_op_mem_32_or_64(instruction, Register::RAX, Register::RAX, TupleType::None, false);
		} else if self.state.address_size == OpSize::Size32 {
			let _ = self.read_op_mem_32_or_64(instruction, Register::EAX, Register::EAX, TupleType::None, false);
		} else {
			self.read_op_mem_16(instruction, TupleType::None);
			if self.invalid_check_mask != 0 {
				self.set_invalid_instruction();
			}
		}
	}

	#[inline(always)]
	#[cfg(not(feature = "no_evex"))]
	pub(self) fn read_op_mem_tuple_type(&mut self, instruction: &mut Instruction, tuple_type: TupleType) {
		debug_assert_eq!(EncodingKind::EVEX, self.state.encoding());
		if self.state.address_size == OpSize::Size64 {
			let _ = self.read_op_mem_32_or_64(instruction, Register::RAX, Register::RAX, tuple_type, false);
		} else if self.state.address_size == OpSize::Size32 {
			let _ = self.read_op_mem_32_or_64(instruction, Register::EAX, Register::EAX, tuple_type, false);
		} else {
			self.read_op_mem_16(instruction, tuple_type);
		}
	}

	#[inline(always)]
	#[cfg(any(not(feature = "no_evex"), not(feature = "no_vex"), not(feature = "no_xop")))]
	pub(self) fn read_op_mem_vsib(&mut self, instruction: &mut Instruction, vsib_index: Register, tuple_type: TupleType) {
		let is_valid;
		if self.state.address_size == OpSize::Size64 {
			is_valid = self.read_op_mem_32_or_64(instruction, Register::RAX, vsib_index, tuple_type, true);
		} else if self.state.address_size == OpSize::Size32 {
			is_valid = self.read_op_mem_32_or_64(instruction, Register::EAX, vsib_index, tuple_type, true);
		} else {
			self.read_op_mem_16(instruction, tuple_type);
			is_valid = false;
		}
		if self.invalid_check_mask != 0 && !is_valid {
			self.set_invalid_instruction();
		}
	}

	// It's small enough that the compiler wants to inline it but almost no-one will
	// disassemble code with 16-bit addressing.
	#[inline(never)]
	fn read_op_mem_16(&mut self, instruction: &mut Instruction, tuple_type: TupleType) {
		debug_assert!(self.state.address_size == OpSize::Size16);
		debug_assert!(self.state.rm <= 7);
		let (mut base_reg, index_reg) = unsafe { *MEM_REGS_16.get_unchecked(self.state.rm as usize) };
		match self.state.mod_ {
			0 => {
				if self.state.rm == 6 {
					super::instruction_internal::internal_set_memory_displ_size(instruction, 2);
					self.displ_index = self.data_ptr as usize;
					instruction.set_memory_displacement(self.read_u16() as u32);
					base_reg = Register::None;
					debug_assert_eq!(Register::None, index_reg);
				}
			}
			1 => {
				super::instruction_internal::internal_set_memory_displ_size(instruction, 1);
				self.displ_index = self.data_ptr as usize;
				if tuple_type == TupleType::None {
					instruction.set_memory_displacement(self.read_u8() as i8 as u16 as u32);
				} else {
					instruction.set_memory_displacement(self.disp8n(tuple_type).wrapping_mul(self.read_u8() as i8 as u32) as u16 as u32);
				}
			}
			_ => {
				debug_assert_eq!(2, self.state.mod_);
				super::instruction_internal::internal_set_memory_displ_size(instruction, 2);
				self.displ_index = self.data_ptr as usize;
				instruction.set_memory_displacement(self.read_u16() as u32);
			}
		}
		super::instruction_internal::internal_set_memory_base(instruction, base_reg);
		super::instruction_internal::internal_set_memory_index(instruction, index_reg);
	}

	// Returns `true` if the SIB byte was read
	#[cfg_attr(has_must_use, must_use)]
	fn read_op_mem_32_or_64(
		&mut self, instruction: &mut Instruction, base_reg: Register, index_reg: Register, tuple_type: TupleType, is_vsib: bool,
	) -> bool {
		debug_assert!(self.state.address_size == OpSize::Size32 || self.state.address_size == OpSize::Size64);
		let sib: u32;
		let displ_size_scale: u32;
		let displ: u32;
		match self.state.mod_ {
			0 => match self.state.rm {
				4 => {
					sib = self.read_u8() as u32;
					displ_size_scale = 0;
					displ = 0;
				}
				5 => {
					if self.state.address_size == OpSize::Size64 {
						super::instruction_internal::internal_set_memory_displ_size(instruction, 4);
					} else {
						super::instruction_internal::internal_set_memory_displ_size(instruction, 3);
					}
					self.displ_index = self.data_ptr as usize;
					instruction.set_memory_displacement(self.read_u32() as u32);
					if self.is64_mode {
						if self.state.address_size == OpSize::Size64 {
							super::instruction_internal::internal_set_memory_base(instruction, Register::RIP);
						} else {
							super::instruction_internal::internal_set_memory_base(instruction, Register::EIP);
						}
					}
					return false;
				}
				_ => {
					debug_assert!(self.state.rm <= 7 && self.state.rm != 4 && self.state.rm != 5);
					super::instruction_internal::internal_set_memory_base_u32(
						instruction,
						self.state.extra_base_register_base + self.state.rm + base_reg as u32,
					);
					return false;
				}
			},
			1 => {
				if self.state.rm == 4 {
					sib = self.read_u8() as u32;
					displ_size_scale = 1;
					self.displ_index = self.data_ptr as usize;
					if tuple_type == TupleType::None {
						displ = self.read_u8() as i8 as u32;
					} else {
						displ = self.disp8n(tuple_type).wrapping_mul(self.read_u8() as i8 as u32);
					}
				} else {
					debug_assert!(self.state.rm <= 7 && self.state.rm != 4);
					super::instruction_internal::internal_set_memory_displ_size(instruction, 1);
					self.displ_index = self.data_ptr as usize;
					if tuple_type == TupleType::None {
						instruction.set_memory_displacement(self.read_u8() as i8 as u32);
					} else {
						instruction.set_memory_displacement(self.disp8n(tuple_type).wrapping_mul(self.read_u8() as i8 as u32));
					}
					super::instruction_internal::internal_set_memory_base_u32(
						instruction,
						self.state.extra_base_register_base + self.state.rm + base_reg as u32,
					);
					return false;
				}
			}
			_ => {
				debug_assert_eq!(2, self.state.mod_);
				if self.state.rm == 4 {
					sib = self.read_u8() as u32;
					displ_size_scale = if self.state.address_size == OpSize::Size64 { 4 } else { 3 };
					self.displ_index = self.data_ptr as usize;
					displ = self.read_u32() as u32;
				} else {
					debug_assert!(self.state.rm <= 7 && self.state.rm != 4);
					if self.state.address_size == OpSize::Size64 {
						super::instruction_internal::internal_set_memory_displ_size(instruction, 4);
					} else {
						super::instruction_internal::internal_set_memory_displ_size(instruction, 3);
					}
					self.displ_index = self.data_ptr as usize;
					instruction.set_memory_displacement(self.read_u32() as u32);
					super::instruction_internal::internal_set_memory_base_u32(
						instruction,
						self.state.extra_base_register_base + self.state.rm + base_reg as u32,
					);
					return false;
				}
			}
		}

		let index = ((sib >> 3) & 7) + self.state.extra_index_register_base;
		let base = sib & 7;

		super::instruction_internal::internal_set_memory_index_scale(instruction, sib >> 6);
		if !is_vsib {
			if index != 4 {
				super::instruction_internal::internal_set_memory_index_u32(instruction, index + index_reg as u32);
			}
		} else {
			super::instruction_internal::internal_set_memory_index_u32(
				instruction,
				index + self.state.extra_index_register_base_vsib + index_reg as u32,
			);
		}

		if base == 5 && self.state.mod_ == 0 {
			if self.state.address_size == OpSize::Size64 {
				super::instruction_internal::internal_set_memory_displ_size(instruction, 4);
			} else {
				super::instruction_internal::internal_set_memory_displ_size(instruction, 3);
			}
			self.displ_index = self.data_ptr as usize;
			instruction.set_memory_displacement(self.read_u32() as u32);
		} else {
			super::instruction_internal::internal_set_memory_base_u32(instruction, base + self.state.extra_base_register_base + base_reg as u32);
			super::instruction_internal::internal_set_memory_displ_size(instruction, displ_size_scale);
			instruction.set_memory_displacement(displ);
		}
		true
	}

	#[cfg_attr(has_must_use, must_use)]
	fn disp8n(&self, tuple_type: TupleType) -> u32 {
		match tuple_type {
			TupleType::None => 1,
			TupleType::Full_128 => {
				if (self.state.flags & StateFlags::B) != 0 {
					if (self.state.flags & StateFlags::W) != 0 {
						8
					} else {
						4
					}
				} else {
					16
				}
			}
			TupleType::Full_256 => {
				if (self.state.flags & StateFlags::B) != 0 {
					if (self.state.flags & StateFlags::W) != 0 {
						8
					} else {
						4
					}
				} else {
					32
				}
			}
			TupleType::Full_512 => {
				if (self.state.flags & StateFlags::B) != 0 {
					if (self.state.flags & StateFlags::W) != 0 {
						8
					} else {
						4
					}
				} else {
					64
				}
			}
			TupleType::Half_128 => {
				if (self.state.flags & StateFlags::B) != 0 {
					4
				} else {
					8
				}
			}
			TupleType::Half_256 => {
				if (self.state.flags & StateFlags::B) != 0 {
					4
				} else {
					16
				}
			}
			TupleType::Half_512 => {
				if (self.state.flags & StateFlags::B) != 0 {
					4
				} else {
					32
				}
			}
			TupleType::Full_Mem_128 => 16,
			TupleType::Full_Mem_256 => 32,
			TupleType::Full_Mem_512 => 64,
			TupleType::Tuple1_Scalar => {
				if (self.state.flags & StateFlags::W) != 0 {
					8
				} else {
					4
				}
			}
			TupleType::Tuple1_Scalar_1 => 1,
			TupleType::Tuple1_Scalar_2 => 2,
			TupleType::Tuple1_Scalar_4 => 4,
			TupleType::Tuple1_Scalar_8 => 8,
			TupleType::Tuple1_Fixed_4 => 4,
			TupleType::Tuple1_Fixed_8 => 8,
			TupleType::Tuple2 => {
				if (self.state.flags & StateFlags::W) != 0 {
					16
				} else {
					8
				}
			}
			TupleType::Tuple4 => {
				if (self.state.flags & StateFlags::W) != 0 {
					32
				} else {
					16
				}
			}
			TupleType::Tuple8 => {
				debug_assert!((self.state.flags & StateFlags::W) == 0);
				32
			}
			TupleType::Tuple1_4X => 16,
			TupleType::Half_Mem_128 => 8,
			TupleType::Half_Mem_256 => 16,
			TupleType::Half_Mem_512 => 32,
			TupleType::Quarter_Mem_128 => 4,
			TupleType::Quarter_Mem_256 => 8,
			TupleType::Quarter_Mem_512 => 16,
			TupleType::Eighth_Mem_128 => 2,
			TupleType::Eighth_Mem_256 => 4,
			TupleType::Eighth_Mem_512 => 8,
			TupleType::Mem128 => 16,
			TupleType::MOVDDUP_128 => 8,
			TupleType::MOVDDUP_256 => 32,
			TupleType::MOVDDUP_512 => 64,
		}
	}

	/// Gets the offsets of the constants (memory displacement and immediate) in the decoded instruction.
	/// The caller can check if there are any relocations at those addresses.
	///
	/// # Arguments
	///
	/// * `instruction`: The latest instruction that was decoded by this decoder
	///
	/// # Examples
	///
	/// ```
	/// use iced_x86::*;
	///
	/// // nop
	/// // xor dword ptr [rax-5AA5EDCCh],5Ah
	/// //                  00  01  02  03  04  05  06
	/// //                \opc\mrm\displacement___\imm
	/// let bytes = b"\x90\x83\xB3\x34\x12\x5A\xA5\x5A";
	/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
	/// decoder.set_ip(0x1234_5678);
	/// assert_eq!(Code::Nopd, decoder.decode().code());
	/// let instr = decoder.decode();
	/// let co = decoder.get_constant_offsets(&instr);
	///
	/// assert!(co.has_displacement());
	/// assert_eq!(2, co.displacement_offset());
	/// assert_eq!(4, co.displacement_size());
	/// assert!(co.has_immediate());
	/// assert_eq!(6, co.immediate_offset());
	/// assert_eq!(1, co.immediate_size());
	/// // It's not an instruction with two immediates (e.g. enter)
	/// assert!(!co.has_immediate2());
	/// assert_eq!(0, co.immediate_offset2());
	/// assert_eq!(0, co.immediate_size2());
	/// ```
	#[cfg_attr(has_must_use, must_use)]
	#[cfg_attr(feature = "cargo-clippy", allow(clippy::missing_inline_in_public_items))]
	pub fn get_constant_offsets(&self, instruction: &Instruction) -> ConstantOffsets {
		let mut constant_offsets = ConstantOffsets::default();

		let displ_size = instruction.memory_displ_size();
		if displ_size != 0 {
			constant_offsets.displacement_offset = (self.displ_index - self.instr_start_data_ptr as usize) as u8;
			if displ_size == 8 && (self.state.flags & StateFlags::ADDR64) == 0 {
				constant_offsets.displacement_size = 4;
			} else {
				constant_offsets.displacement_size = displ_size as u8;
			}
		}

		if (self.state.flags & StateFlags::NO_IMM) == 0 {
			let mut extra_imm_sub = 0;
			for i in (0..instruction.op_count()).rev() {
				match instruction.op_kind(i) {
					OpKind::Immediate8 | OpKind::Immediate8to16 | OpKind::Immediate8to32 | OpKind::Immediate8to64 => {
						constant_offsets.immediate_offset = (instruction.len() - extra_imm_sub - 1) as u8;
						constant_offsets.immediate_size = 1;
						break;
					}

					OpKind::Immediate16 => {
						constant_offsets.immediate_offset = (instruction.len() - extra_imm_sub - 2) as u8;
						constant_offsets.immediate_size = 2;
						break;
					}

					OpKind::Immediate32 | OpKind::Immediate32to64 => {
						constant_offsets.immediate_offset = (instruction.len() - extra_imm_sub - 4) as u8;
						constant_offsets.immediate_size = 4;
						break;
					}

					OpKind::Immediate64 => {
						constant_offsets.immediate_offset = (instruction.len() - extra_imm_sub - 8) as u8;
						constant_offsets.immediate_size = 8;
						break;
					}

					OpKind::Immediate8_2nd => {
						constant_offsets.immediate_offset2 = (instruction.len() - 1) as u8;
						constant_offsets.immediate_size2 = 1;
						extra_imm_sub = 1;
					}

					OpKind::NearBranch16 => {
						if (self.state.flags & StateFlags::BRANCH_IMM8) != 0 {
							constant_offsets.immediate_offset = (instruction.len() - 1) as u8;
							constant_offsets.immediate_size = 1;
						} else if (self.state.flags & StateFlags::XBEGIN) == 0 {
							constant_offsets.immediate_offset = (instruction.len() - 2) as u8;
							constant_offsets.immediate_size = 2;
						} else {
							debug_assert!((self.state.flags & StateFlags::XBEGIN) != 0);
							if self.state.operand_size != OpSize::Size16 {
								constant_offsets.immediate_offset = (instruction.len() - 4) as u8;
								constant_offsets.immediate_size = 4;
							} else {
								constant_offsets.immediate_offset = (instruction.len() - 2) as u8;
								constant_offsets.immediate_size = 2;
							}
						}
					}

					OpKind::NearBranch32 | OpKind::NearBranch64 => {
						if (self.state.flags & StateFlags::BRANCH_IMM8) != 0 {
							constant_offsets.immediate_offset = (instruction.len() - 1) as u8;
							constant_offsets.immediate_size = 1;
						} else if (self.state.flags & StateFlags::XBEGIN) == 0 {
							constant_offsets.immediate_offset = (instruction.len() - 4) as u8;
							constant_offsets.immediate_size = 4;
						} else {
							debug_assert!((self.state.flags & StateFlags::XBEGIN) != 0);
							if self.state.operand_size != OpSize::Size16 {
								constant_offsets.immediate_offset = (instruction.len() - 4) as u8;
								constant_offsets.immediate_size = 4;
							} else {
								constant_offsets.immediate_offset = (instruction.len() - 2) as u8;
								constant_offsets.immediate_size = 2;
							}
						}
					}

					OpKind::FarBranch16 => {
						constant_offsets.immediate_offset = (instruction.len() - (2 + 2)) as u8;
						constant_offsets.immediate_size = 2;
						constant_offsets.immediate_offset2 = (instruction.len() - 2) as u8;
						constant_offsets.immediate_size2 = 2;
					}

					OpKind::FarBranch32 => {
						constant_offsets.immediate_offset = (instruction.len() - (4 + 2)) as u8;
						constant_offsets.immediate_size = 4;
						constant_offsets.immediate_offset2 = (instruction.len() - 2) as u8;
						constant_offsets.immediate_size2 = 2;
					}

					_ => {}
				}
			}
		}

		constant_offsets
	}
}

/// An iterator that borrows a [`Decoder`] and decodes instructions until there's
/// no more data available. See [`Decoder::iter()`].
///
/// [`Decoder`]: struct.Decoder.html
/// [`Decoder::iter()`]: struct.Decoder.html#method.iter
#[derive(Debug)]
pub struct DecoderIter<'a: 'b, 'b> {
	decoder: &'b mut Decoder<'a>,
}

impl<'a, 'b> Iterator for DecoderIter<'a, 'b> {
	type Item = Instruction;

	#[inline]
	fn next(&mut self) -> Option<Self::Item> {
		if self.decoder.can_decode() {
			Some(self.decoder.decode())
		} else {
			None
		}
	}
}

#[cfg(has_fused_iterator)]
impl<'a, 'b> FusedIterator for DecoderIter<'a, 'b> {}

/// An iterator that consumes a [`Decoder`] and decodes instructions until there's
/// no more data available.
///
/// [`Decoder`]: struct.Decoder.html
#[derive(Debug)]
pub struct DecoderIntoIter<'a> {
	decoder: Decoder<'a>,
}

impl<'a> Iterator for DecoderIntoIter<'a> {
	type Item = Instruction;

	#[inline]
	fn next(&mut self) -> Option<Self::Item> {
		if self.decoder.can_decode() {
			Some(self.decoder.decode())
		} else {
			None
		}
	}
}

#[cfg(has_fused_iterator)]
impl<'a> FusedIterator for DecoderIntoIter<'a> {}

impl<'a> IntoIterator for Decoder<'a> {
	type Item = Instruction;
	type IntoIter = DecoderIntoIter<'a>;

	#[cfg_attr(has_must_use, must_use)]
	#[inline]
	fn into_iter(self) -> Self::IntoIter {
		DecoderIntoIter { decoder: self }
	}
}

impl<'a: 'b, 'b> IntoIterator for &'b mut Decoder<'a> {
	type Item = Instruction;
	type IntoIter = DecoderIter<'a, 'b>;

	#[inline]
	fn into_iter(self) -> Self::IntoIter {
		DecoderIter { decoder: self }
	}
}
